import _ from 'lodash';
import { ipcMain, Event } from 'electron';
import lowdb from 'lowdb';
import lowFileSync from 'lowdb/adapters/FileSync';
import IElectronModule from './bg_base';
import { IpcConnnectionFile, IpcConnnectionGetByPath, IpcConnnectionSetByPath } from '@/plugin/ipc_renderer_ex';

/** 连接 lowdb 数据库 */
export const LOWDB_CONN = "lowdb-conn";
export const LOWDB_CONN_RET = "lowdb-conn-ret";
/** 从 lowdb 数据库的指定路径获取数据 */
export const LOWDB_GET = "lowdb-get";
export const LOWDB_GET_RET = "lowdb-get-ret";
/** 从 lowdb 数据库的指定路径保存数据 */
export const LOWDB_SET = "lowdb-set";
export const LOWDB_SET_RET = "lowdb-set-ret";


// 定义ipc接口
declare module '@/plugin/ipc_renderer_ex' {
    interface IpcSendTypes {
        [LOWDB_CONN]: IpcSendTypeNode<IpcConnnectionFile, IpcReturnDBKey>
        [LOWDB_GET]: IpcSendTypeNode<IpcConnnectionGetByPath, IpcReturnValue<any>>
        [LOWDB_SET]: IpcSendTypeNode<IpcConnnectionSetByPath<any>, IpcReturnBase>
    }
}

declare function IDBWork(db: lowdb.LoDashExplicitSyncWrapper<any>): lowdb.LoDashExplicitSyncWrapper<any>;



/**
 * lowdb的简单包装
 */
class LowDBEasy implements IElectronModule {

    private _database_map: Map<string, lowdb.LowdbSync<any>> = new Map<string, lowdb.LowdbSync<any>>();

    install(): void {
        ipcMain.on(LOWDB_CONN, this.conn.bind(this));
        ipcMain.on(LOWDB_GET, this.getValue.bind(this));
        ipcMain.on(LOWDB_SET, this.setValue.bind(this));
    }

    /**
     * 获取数据库连接并进行处理
     * @param key 数据库连接的关键字
     * @param event el事件对象
     * @param callback 获取到数据库连接后的处理方法
     */
    private getDB(
        key: string,
        event: Event,
        ret_channel: string,
        callback: (db: lowdb.LowdbSync<any>) => void
    ): void {
        let db = this._database_map.get(key);
        if (!_.isNil(db)) {
            callback(db)
        }
        else {
            event.sender.send(ret_channel, {
                status: "error",
                message: "no connection"
            });
        }
    }

    /**
     * 连接数据库
     * @param event 
     * @param param1 
     */
    private conn(
        event: Event,
        { key = "", file = "db.json" }: IpcConnnectionFile
    ): void {
        let db_key = _.isEmpty(key)
            ? (_.isEmpty(file) ? "db" : file) + "_" + _.random(0, 99999)
            : key;

        let adapter = new lowFileSync(file);
        let db = lowdb(adapter);

        if (db) {
            this._database_map.set(db_key, db);
            event.sender.send(LOWDB_CONN_RET, {
                status: "success",
                message: "数据库连接成功",
                db_key
            });
        } else {
            event.sender.send(LOWDB_CONN_RET, {
                status: "error",
                message: "数据库连接失败",
                db_key
            });
        }

    }

    /**
     * 获取数据
     * @param event 
     * @param param1 
     */
    private getValue(
        event: Event,
        { key = "", path = "" }: IpcConnnectionGetByPath
    ) {
        if (_.isNil(path) || path.length < 1) {
            event.sender.send(LOWDB_GET_RET, {
                status: "error",
                message: "请输入有效路径。参考：{path:Many<string | number | symbol>}"
            });
        }
        else {
            this.getDB(key, event, LOWDB_GET_RET, db => {
                event.sender.send(LOWDB_GET_RET, {
                    status: "success",
                    message: "获取成功",
                    value: db.get(path).value()
                });
            });
        }
    }

    private setValue(
        event: Event,
        { key = "", path = "", value = null }: IpcConnnectionSetByPath<any>
    ) {
        if (_.isNil(path) || path.length < 1) {
            event.sender.send(LOWDB_SET_RET, {
                status: "error",
                message: "请输入有效路径。参考：{path:Many<string | number | symbol>}"
            });
        }
        else {
            this.getDB(key, event, LOWDB_SET_RET, db => {
                db.set(path, value).write();
                event.sender.send(LOWDB_SET_RET, {
                    status: "success",
                    message: "设置成功"
                });
            });
        }
    }
}

export default new LowDBEasy();